package com.tsfyun.common.base.util;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.tsfyun.common.base.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @date 2019/05/27
 */
@Slf4j
public final class StringUtils extends StrUtil{

    /**
     * 匹配所有特殊字符的正则表达式
     */
    public static final String SPECIAL_CHARACTER_REGEX = "[`~!@#$%^&*()\\-+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）—_+|{}【】‘；：”“’。，、\"？\\s]";

    public static final Pattern SPECIAL_CHARACTER_PATTERN = Pattern.compile(SPECIAL_CHARACTER_REGEX);

    /**
     * 中文正则
     */
    public static final String CHINESE_REGEX = "[\u4e00-\u9fa5]";

    /**
     * 匹配括号中间内容
     */
    private static final Pattern BRACKET_CONTENT_PATTERN = Pattern.compile("(?<=\\()(.+?)(?=\\))");

    /**英文公司正则*/
    public static final String ENGLISH_REGEX = "[A-Za-z][.|,|&|(|)|\\s]+$" ;

    public static final Pattern ENGLISH_PATTERN = Pattern.compile(ENGLISH_REGEX) ;

    private StringUtils() {
    }

    public static final boolean isEmpty(String foo) {
        return (foo == null || foo.trim().length() == 0);
    }

    public static final boolean isEmpty(Object foo) {
        return (foo == null || foo.toString().trim().length() == 0);
    }

    public static final boolean isNotEmpty(String foo) {
        return (null != foo && foo.trim().length() > 0);
    }

    public static final boolean isNotEmpty(Object foo) {
        return (null != foo && foo.toString().trim().length() > 0);
    }

    public static String removeSpecialSymbol(String str) {
        String newStr = "";
        if (isNotEmpty(str)) {
            str = str.replaceAll("\n", "");//回车符
            str = str.replaceAll("\t ", "");//水平制表符
            str = str.replaceAll("\r ", "");//换行
            str = str.replace(String.valueOf((char) 160), " ");
            newStr = str.trim();
        }
        return newStr;
    }

    public static String removeSpecialSymbol(Object object) {
        if (object == null) {
            return "";
        }
        return removeSpecialSymbol(object.toString());
    }

    /**
     * 生成6位随机数
     *
     * @return
     */
    public static String randomStr6() {
        Random random = new Random();
        int min = 100000;
        int max = 999999;
        int rand_int = random.nextInt(max) % (max - min + 1) + min;
        return rand_int + "";
    }

    public static int randomInt6() {
        Random random = new Random();
        int min = 100000;
        int max = 999999;
        int rand_int = random.nextInt(max) % (max - min + 1) + min;
        return rand_int;
    }

    /**
     * 生成4位随机数
     *
     * @return
     */
    public static String randomStr4() {
        Random random = new Random();
        int min = 1000;
        int max = 9999;
        int rand_int = random.nextInt(max) % (max - min + 1) + min;
        return rand_int + "";
    }

    /**
     * =
     * 生成UUID
     *
     * @return
     */
    public static String UUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 将字节数组进行MD5编码并返回
     *
     * @param arrIn 需要编码的字节数组
     * @return String 进行MD5编码后的字串
     * @throws Exception
     */
    public static String getHexMD5Str(byte[] arrIn) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] arrB = md.digest(arrIn);
            StringBuffer sb = new StringBuffer(32);
            for (int i = 0; i < arrB.length; ++i) {
                int intTmp = arrB[i];
                while (intTmp < 0) {
                    intTmp += 256;
                }
                if (intTmp < 16) {
                    sb.append('0');
                }
                sb.append(Integer.toString(intTmp, 16));
            }
            return sb.toString().toUpperCase();
        } catch (Exception e) {

        }
        return null;
    }

    /**
     * 计算一个字符串的长度，汉字当成两个字符计算，ascii英文字符当成一个。
     *
     * @param aStr 要计算长度的目标字符串
     * @return 计算出的长度
     */
    public static int lengthOfHZ(String aStr) {
        if (StringUtils.isEmpty(aStr)) {
            return 0;
        }
        char c;
        int length = 0;
        for (int i = 0; i < aStr.length(); i++) {
            c = aStr.charAt(i);
            if (c >= 127) {
                length += 2;
            } else {
                length += 1;
            }
        }
        return length;
    }

    /**
     * =
     * 验证字符串是否为数字
     *
     * @param str
     * @return
     */
    public static boolean isBigDecimal(String str) {
        if (!StringUtils.isEmpty(str)) {
            try {
                new BigDecimal(str);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    /**
     * =
     * 四舍五入保留2位小数
     *
     * @param arg
     * @return
     */
    public static BigDecimal rounded2(String arg) {
        return rounded2(new BigDecimal(arg));
    }

    /**
     * =
     * 四舍五入保留2位小数
     *
     * @param arg
     * @return
     */
    public static BigDecimal rounded2(BigDecimal arg) {
        DecimalFormat df = new DecimalFormat("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return new BigDecimal(df.format(arg));
    }

    public static BigDecimal rounded4(BigDecimal arg) {
        DecimalFormat df = new DecimalFormat("0.0000");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return new BigDecimal(df.format(arg));
    }

    public static BigDecimal rounded6(String arg) {
        return rounded6(new BigDecimal(arg));
    }

    public static BigDecimal rounded6(BigDecimal arg) {
        DecimalFormat df = new DecimalFormat("0.000000");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return new BigDecimal(df.format(arg));
    }

    public static String autoFillZero(Integer idx,String pattern){
        DecimalFormat df = new DecimalFormat(pattern);
        return df.format(idx);
    }

    public static BigDecimal rounded(BigDecimal arg) {
        DecimalFormat df = new DecimalFormat("0");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return new BigDecimal(df.format(arg));
    }

    /**
     * =
     * 验证字符串是否为整数
     *
     * @param str
     * @return
     */
    public static boolean isBigInteger(String str) {
        if (!StringUtils.isEmpty(str)) {
            try {
                new BigInteger(str);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    public static String escape(String src) {
        if (isEmpty(src)) {
            return "";
        }
        int i;
        char j;
        StringBuffer tmp = new StringBuffer();
        tmp.ensureCapacity(src.length() * 6);
        for (i = 0; i < src.length(); i++) {
            j = src.charAt(i);
            if (Character.isDigit(j) || Character.isLowerCase(j)
                    || Character.isUpperCase(j))
                tmp.append(j);
            else if (j < 256) {
                tmp.append("%");
                if (j < 16)
                    tmp.append("0");
                tmp.append(Integer.toString(j, 16));
            } else {
                tmp.append("%u");
                tmp.append(Integer.toString(j, 16));
            }
        }
        return tmp.toString();
    }

    public static String formatCurrency(BigDecimal arg) {
        if (arg == null) {
            return "0.00";
        }
        DecimalFormat df = new DecimalFormat("###,###,###,##0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        return df.format(arg);
    }

    /**
     * 二进制转字符串
     */
    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();
    }

    /**
     * 字符串去左右空格
     */
    public static String null2EmptyWithTrim(String s) {
        if (s == null) {
            return "";
        } else {
            return s.trim();
        }
    }

    /**
     * 字符串去左右空格
     */
    public static String null2EmptyWithTrim(Object s) {
        if (s == null) {
            return "";
        } else {
            return s.toString().trim();
        }
    }

    /**
     * 字符串去左右空格
     */
    public static String null2EmptyWithTrimNew(Object s) {

        if (s == null || "NULL".equalsIgnoreCase(s.toString())) {
            return "";
        } else {
            return s.toString().trim();
        }
    }

    /**
     * 计算一个字符串的长度，汉字当成两个字符计算，ascii英文字符当成一个。
     *
     * @param aStr 要计算长度的目标字符串
     * @return 计算出的长度
     */
    public static int lengthOfCN(String aStr) {
        char c;
        int length = 0;
        if (isNotEmpty(aStr)) {
            for (int i = 0; i < aStr.length(); i++) {
                c = aStr.charAt(i);
                if (c >= 127) {
                    length += 2;
                } else {
                    length += 1;
                }
            }
        }
        return length;
    }

    /**
     * 字符串首字母大写或小写
     */
    public static String firstLetterUpperOrLower(String str, boolean isLowerCase) {
        if (isNotEmpty(str)) {
            if (str.length() == 1) {
                return isLowerCase ? str.toLowerCase() : str.toUpperCase();
            } else {
                String first = str.substring(0, 1).toLowerCase();
                first = isLowerCase ? first.toLowerCase() : first.toUpperCase();
                return (first + str.substring(1));
            }
        }
        return str;
    }

    /**
     * 去除字符串所有特殊字符
     */
    public static String removeAllSpecialChar(String str) {
        Matcher m = SPECIAL_CHARACTER_PATTERN.matcher(str);
        return m.replaceAll("").trim();
    }

    /**
     * 判断str是否在strArr中
     */
    public static boolean strInArray(String str, String[] strArr) {
        for (String s : strArr) {
            if (str.equals(s)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断字符串中是否包含中文
     */
    public static boolean isContainChinese(String str) {
        Matcher m = SPECIAL_CHARACTER_PATTERN.matcher(str);
        return m.find();
    }

    /**
     * 获取字符串中所有中文
     */
    public static String getAllChineseInStr(String str) {
        return str.replaceAll("[^\u4e00-\u9fa5]", "");
    }

    /**
     * 获取括号内内容
     *
     * @param str
     */
    public static String getBracketContent(String str) {
        Matcher matcher = BRACKET_CONTENT_PATTERN.matcher(str);
        if (matcher.find()) {
            return matcher.group(0);
        } else {
            return "";
        }
    }

    /**
     * 左补全字符
     *
     * @param w84PaddingStr 需要补全的字符
     * @param digit         补全后字符的位数
     * @param paddingStr    补全使用的字符
     */
    public static String leftPadding(String w84PaddingStr, int digit, String paddingStr) {
        w84PaddingStr = null2EmptyWithTrim(w84PaddingStr);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < digit - w84PaddingStr.length(); i++) {
            sb.append(paddingStr);
        }
        sb.append(w84PaddingStr);
        return sb.toString();
    }

    /**
     * 右补全字符
     *
     * @param w84PaddingStr 需要补全的字符
     * @param digit         补全后字符的位数
     * @param paddingStr    补全使用的字符
     */
    public static String rightPadding(String w84PaddingStr, int digit, String paddingStr) {
        w84PaddingStr = null2EmptyWithTrim(w84PaddingStr);
        StringBuffer sb = new StringBuffer();
        sb.append(w84PaddingStr);
        for (int i = 0; i < digit - w84PaddingStr.length(); i++) {
            sb.append(paddingStr);
        }
        return sb.toString();
    }

    /**
     * 月份补全 2位
     *
     * @param month 月份
     */
    public static String monthPadding(int month) {
        return leftPadding(Integer.valueOf(month).toString(), 2, "0");
    }

    /**
     * 格式化字符串
     *
     * @param template 模版字符 占位使用%s
     * @param args     参数
     */
    public static String format(String template, Object... args) {
        template = String.valueOf(template);
        StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
        int templateStart = 0;

        int i;
        int placeholderStart;
        for (i = 0; i < args.length; templateStart = placeholderStart + 2) {
            placeholderStart = template.indexOf("%s", templateStart);
            if (placeholderStart == -1) {
                break;
            }

            builder.append(template, templateStart, placeholderStart);
            builder.append(args[i++]);
        }

        builder.append(template.substring(templateStart));
        if (i < args.length) {
            builder.append(" [");
            builder.append(args[i++]);

            while (i < args.length) {
                builder.append(", ");
                builder.append(args[i++]);
            }

            builder.append(']');
        }

        return builder.toString();
    }

    /**
     * 是否存在指定值对应的枚举
     *
     * @param enumClass
     * @param value
     */
    public static Boolean enumContainsValue(Class enumClass, String value) {
        try {
            Enum.valueOf(enumClass, value);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    /**
     * @param json
     * @return
     */
    public final static boolean isJSONValid(String json) {
        try {
            JSONObject.parseObject(json);//不可能直接传json array的
        } catch (ClassCastException | JSONException e) {
            return false;
        }
        return true;
    }

    /**
     * @param json
     * @return
     */
    public final static boolean isJSONArray(String json) {
        try {
            JSONObject.parseArray(json);//不可能直接传json array的
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static boolean isBigDecimal(Object str) {
        if (isEmpty(str)) {
            return false;
        }
        try {
            new BigDecimal(null2EmptyWithTrim(str));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static boolean isInteger(Object str) {
        if (isEmpty(str)) {
            return false;
        }
        try {
            Integer.parseInt(null2EmptyWithTrim(str));
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static boolean isMatch(String regex, String orginal) {
        if (orginal == null || "".equals(orginal.trim())) {
            return false;
        }
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(orginal);
        return matcher.matches();
    }

    /**
     * 正整数
     *
     * @param orginal
     * @return
     */
    public static boolean isPositiveInteger(String orginal) {
        return isMatch("^[1-9]\\d*", orginal);
    }

    /**
     * 负整数
     *
     * @param orginal
     * @return
     */
    public static boolean isNegativeInteger(String orginal) {
        return isMatch("^-[1-9]\\d*", orginal);
    }

    /**
     * 整数（包括负整数、0、正整数）
     *
     * @param orginal
     * @return
     */
    public static boolean isWholeNumber(String orginal) {
        return isMatch("0", orginal) || isPositiveInteger(orginal) || isNegativeInteger(orginal);
    }

    /**
     * 正小数
     *
     * @param orginal
     * @return
     */
    public static boolean isPositiveDecimal(String orginal) {
        return isMatch("\\+{0,1}[0]\\.[1-9]*|\\+{0,1}[1-9]\\d*\\.\\d*", orginal);
    }

    /**
     * 负小数
     *
     * @param orginal
     * @return
     */
    public static boolean isNegativeDecimal(String orginal) {
        return isMatch("^-[0]\\.[1-9]*|^-[1-9]\\d*\\.\\d*", orginal);
    }

    /**
     * 小数
     *
     * @param orginal
     * @return
     */
    public static boolean isDecimal(String orginal) {
        return isMatch("[-+]{0,1}\\d+\\.\\d*|[-+]{0,1}\\d*\\.\\d+", orginal);
    }

    /**
     * 实数
     *
     * @param orginal
     * @return
     */
    public static boolean isRealNumber(String orginal) {
        return isWholeNumber(orginal) || isDecimal(orginal);
    }

    /**
     * 按照指定格式解析字符串型日期值为日期对象
     *
     * @param date    字符串型日期
     * @param pattern 日期格式
     * @return 日期对象
     */
    public static Date parse(String date, String pattern) {
        if (isEmpty(date)) {
            return null;
        }
        DateFormat formater = new SimpleDateFormat(pattern);
        try {
            return formater.parse(date);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 按照指定格式转换日期对象为字符串型日期
     *
     * @param date    日期对象
     * @param pattern 日期格式
     * @return 字符串型日期
     */
    public static String format(Date date, String pattern) {
        if (StringUtils.isEmpty(date)) {
            return "";
        }
        DateFormat formater = new SimpleDateFormat(pattern);
        return formater.format(date);
    }

    /**
     * =
     * 验证是否是一个有效的日期
     *
     * @param dataTimeStr
     * @return
     */
    public static Boolean isDate(String dataTimeStr) {
        if (StringUtils.isEmpty(dataTimeStr)) {
            return false;
        }
        try {
            Date date = parse(dataTimeStr, "yyyyMMdd");
            if (date == null) {
                return false;
            } else {
                //2月转换会有问题
                String formatDate = format(date, "yyyyMMdd");
                return dataTimeStr.equals(formatDate);
            }
        } catch (Exception e) {

        }
        return false;
    }

    /**
     * =
     * 验证是否是一个有效的时间
     *
     * @param dataTimeStr
     * @return
     */
    public static Boolean isDateTime(String dataTimeStr) {
        if (StringUtils.isEmpty(dataTimeStr)) {
            return false;
        }
        try {
            Date date = parse(dataTimeStr, "yyyyMMddHHmmss");
            return date != null;
        } catch (Exception e) {

        }
        return false;
    }

    /**
     * 根据整数位和小数位检查数字的长度
     *
     * @param str
     * @param intergerLength
     * @param preciseLength
     * @return
     */
    public static boolean isValidNumber(String str, int intergerLength, int preciseLength) {
        String regex = "^([0-9]{1," + intergerLength + "}+(.[0-9]{" + preciseLength + "})?$)|(-[0-9]{1," + intergerLength + "}+(.[0-9]{" + preciseLength + "})?$)";
        Pattern pattern = Pattern.compile(regex);
        Matcher match = pattern.matcher(str);
        return match.matches();
    }

    /**
     * 判断时间格式是否合法
     *
     * @param sDate   时间日期
     * @param pattern 日期格式化
     * @return
     */
    public static boolean isLegalDate(String sDate, String pattern) {
        if (StringUtils.isEmpty(sDate) || StringUtils.isEmpty(pattern)) {
            return false;
        }
        DateFormat formatter = new SimpleDateFormat(pattern);
        try {
            Date date = formatter.parse(sDate);
            return sDate.equals(formatter.format(date));
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 生成uuid
     *
     * @return
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }

    public static String getDomain(String url) {
        URL urls;
        try {
            urls = new URL(url);
        } catch (MalformedURLException e) {
            log.info("build Url error:----->>>>>" + url, e);
            return null;
        }
        return urls.getHost();
    }

    public static String convertUrl(String url, String newDomain) {
        URL urls = null;
        try {
            urls = new URL(url);
        } catch (MalformedURLException e) {
            log.info("build Url error:----->>>>>" + url, e);
            return url;
        }
        String host = urls.getHost();// 获取主机名
        String protocol = urls.getProtocol();//协议
        String newUrl = url.replace("https://", "").replace("http://", "");
        StringBuilder sb = new StringBuilder();
        sb.append(protocol).append("://").append(newDomain).append("/");
        String[] newUrlAry = newUrl.split("/");
        IntStream.range(1, newUrl.split("/").length).forEach(idx -> {
            sb.append(newUrlAry[idx]).append("/");
        });
        //去掉最后一个/
        sb.deleteCharAt(sb.length() - 1);
        System.out.println(sb);
        return sb.toString();
    }



    public static BigDecimal rounded4(String arg) {
        return rounded4(new BigDecimal(arg));
    }

    /**
     * 加密，先采用sha256，再采用md5
     *
     * @param str
     * @return
     */
    public static String encrySha(String str) {
        return SecureUtil.md5(SecureUtil.sha256(str)).toUpperCase();
    }

    /**
     * 首字母转小写
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0)))
            return s;
        else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * 字符串转集合
     * @param str
     * @return
     */
    public static List<Long> stringToLongs(String str){
        if(isEmpty(str)){return null;}
        return Arrays.asList(StrUtil.split(str,",")).stream().map(Long::valueOf).collect(Collectors.toList());
    }

    public static String trimSpecialChar(String val) {
        Matcher m = SPECIAL_CHARACTER_PATTERN.matcher(val);
        return m.replaceAll("").trim();
    }

    /**
     * 获取字符串是否为英文名称
     */
    public static Boolean checkEnglishName(String str){
        Boolean containChinese = isContainChinese(str);
        if(containChinese) {
            return false;
        }
        Matcher m = ENGLISH_PATTERN.matcher(str);
        return  m.find() ;
    }

    /**
     * 正整数
     * @param orginal
     * @return
     */
    public static boolean isPositiveIntegerWithLength(String orginal,int length) {
        return isMatch(String.format("^[1-9][0-9]{0,%d}$",length - 1), orginal);
    }

    /**
     * 根据整数位和小数位检查数字的长度（正数）
     * @param str
     * @param intergerLength
     * @param preciseLength
     * @return
     */
    public static boolean isPositiveValidNumber(String str,int intergerLength,int preciseLength) {
        String regex = "^([0-9]{1," + intergerLength +"}+(.[0-9]{0," + preciseLength + "})?$)";
        Pattern pattern = Pattern.compile(regex);
        Matcher match = pattern.matcher(str);
        return match.matches();
    }

    /**
     * 包含多少个字符
     * @param content 待匹配内容
     * @param charForSearch  搜索字符
     * @return
     */
    public static int count(String content, CharSequence charForSearch) {
        if(isEmpty(content) || isEmpty(charForSearch)) {
            return 0;
        }
        //去除所有空格
        content = content.replaceAll("\\s+", "");
        charForSearch = charForSearch.toString().replaceAll("\\s+", "");
        int count = 0;
        char[] chars = charForSearch.toString().toCharArray();
        for(int i = 0;i < chars.length;i++) {
            char searchChar = chars[i];
            if(content.indexOf(searchChar) != -1) {
                count++;
            }
        }
        return count;
    }

    /**
     * 获取起始值和结束值之间的随机数（不能等于起始值和结束值）
     * @param start 起始值
     * @param end   结束值
     * @param scale 小数点位数
     * @return
     */
    public static BigDecimal randomRange(int start,int end,int scale) {
        TsfPreconditions.checkArgument(end > start,new ServiceException("结束值必须大于起始值"));
        BigDecimal random =  RandomUtil.randomBigDecimal(new BigDecimal(start),new BigDecimal(end)).setScale(scale,BigDecimal.ROUND_HALF_DOWN);
        //判断是否大于等于上限值
        if(random.compareTo(new BigDecimal(end)) >= 0) {
            random = random.subtract(BigDecimal.ONE);
        }
        //判断是否小于等于下限值
        if(random.compareTo(new BigDecimal(start)) <= 0) {
            random = random.add(BigDecimal.ONE);
        }
        return random;
    }

}
